package com.example.wsServer;

import com.alibaba.fastjson.JSONObject;
import com.example.config.ApplicationContextProvider;
import com.example.dto.ResultDTO;
import com.example.netty.NettyUtil;
import com.example.netty.nettyUserManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Author by admin, Email xx@xx.com, Date on 2020/5/9.
 * PS: Not easy to write code, please indicate.
 * 建立通道，拿到数据，推送客户端。
 */
@Slf4j
public class MyWebSocketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static ObjectMapper MAPPER = new ObjectMapper();

    // 送Spring容器中获取消息监听器容器,处理订阅消息sysNotice
    SimpleMessageListenerContainer sysNoticeContainer = (SimpleMessageListenerContainer) ApplicationContextProvider.getApplicationContext()
            .getBean("sysNoticeContainer");
    //获取点赞监听容器
    SimpleMessageListenerContainer userNoticeContainer = (SimpleMessageListenerContainer) ApplicationContextProvider.getApplicationContext()
            .getBean("userNoticeContainer");
    //从Spring容器中获取RabbitTemplate
    RabbitTemplate rabbitTemplate = ApplicationContextProvider.getApplicationContext()
            .getBean(RabbitTemplate.class);
    //存放WebSocket连接Map，根据用户id存放
    public static ConcurrentHashMap<String, Channel> userChannelMap = new ConcurrentHashMap();


    //用户请求WebSocket服务端，执行的方法
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        JSONObject json = JSONObject.parseObject(msg.text());
        int code = json.getInteger("code");
        nettyUserManager.addChannel(ctx.channel());
        switch (code){
            case 10086:
                Channel channel = ctx.channel();
                log.info("receive pong message, address: {}", NettyUtil.parseChannelRemoteAddr(channel));
                channel.writeAndFlush(new TextWebSocketFrame());
                break;
            default:
                log.warn("The code [{}] can't be auth!!!", code);
                return;
        }
        sysNotionMsg(ctx, msg);
    }

    private void sysNotionMsg(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws IOException {
        //获取用户请求数据并解析
        String json = msg.text();
        System.out.println(json);
        String userId = MAPPER.readTree(json).get("userId").asText();
        //第一次请求的时候，需要建立WebSocket连接
//        Channel channel = userChannelMap.get(userId);
//        if (channel == null) {
//            //获取WebSocket的连接
//            channel = ctx.channel();
//            //把连接放到容器中
//            userChannelMap.put(userId, channel);
//        }
        //只用完成新消息的提醒即可，只需要获取消息的数量
        //获取RabbitMQ的消息内容，并发送给用户
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate);
        //拼接获取队列名称
        String subQueueName = "article_subscribe_" + userId;
        //获取Rabbit的Properties容器
        Properties queueProperties = rabbitAdmin.getQueueProperties(subQueueName);
        //获取消息数量
        int noticeCount = 0;
        //判断Properties是否不为空
        if (queueProperties != null) {
            // 如果不为空，获取消息的数量
            noticeCount = (int) queueProperties.get("QUEUE_MESSAGE_COUNT");
        }
        //---------------------------获取点赞消息队列-----------------------------------------------
        //拼接获取队列名称
        String tupQueueName = "article_thumbup_" + userId;
        //获取Rabbit的Properties容器
        Properties userQueueProperties = rabbitAdmin.getQueueProperties(tupQueueName);
        //获取消息数量
        int userNoticeCount = 0;
        //判断Properties是否不为空
        if (userQueueProperties != null) {
            // 如果不为空，获取消息的数量
            userNoticeCount = (int) userQueueProperties.get("QUEUE_MESSAGE_COUNT");
        }
        //封装返回的数据
        HashMap countMap = new HashMap();
        //发送订阅消息
        countMap.put("sysNoticeCount", noticeCount);
        //发送点赞消息
        countMap.put("userNoticeCount", userNoticeCount  );

        ResultDTO resultDTO = ResultDTO.okOf("系统通知---",countMap);
        //把数据发送给用户
//        channel.writeAndFlush(new TextWebSocketFrame(MAPPER.writeValueAsString(resultDTO)));

        //为用户的消息通知队列注册监听器，便于用户在线的时候，
        //一旦有消息，可以主动推送给用户，不需要用户请求服务器获取数据
        sysNoticeContainer.addQueueNames(tupQueueName);
        sysNoticeContainer.addQueueNames(subQueueName);
//        userNoticeContainer.addQueueNames(userQueueName);
        //把消息从队列里面清空，否则MQ消息监听器会再次消费一次
        if (noticeCount > 0) {
            rabbitAdmin.purgeQueue(tupQueueName, true);
        }
        //把消息从队列里面清空，否则MQ消息监听器会再次消费一次
        if (userNoticeCount > 0) {
            rabbitAdmin.purgeQueue(subQueueName, true);
        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        //添加通道给客户端，当客户段有连接时候
        InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        String hostAddress = inetSocketAddress.getAddress().getHostAddress();
        log.info("有客户端连接，Ip地址为:"+hostAddress);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        //当触发handlerRemoved 客户端关闭连接时，clients会自动移出handler
        //clients.remove(ctx.channel());
        System.out.println(ctx.channel().id().asLongText()+"客户端断开长id");
        System.out.println(ctx.channel().id().asShortText()+"客户端断开断id");
    }


}